package com.yubest.demo.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 为了方便示例，只做简单缓存使用
 * @Author hweiyu
 * @Description
 * @Date 2021/3/23 12:13
 */
@Slf4j
public class CacheUtil {

    private static Map<String, String> map = new ConcurrentHashMap<>();

    private static Map<String, Long> expire = new ConcurrentHashMap<>();

    private static final byte[] LOCK = new byte[0];

    /**
     * 过期时间为 0 时，表明永久有效
     */
    private static final long TIME = 0L;

    static {
        new ExpireTask().start();
    }

    public static <T> T get(String key, Class<T> cls) {
        synchronized (LOCK) {
            String value = map.get(key);
            try {
                if (null != value) {
                    return new ObjectMapper().readValue(value, cls);
                }
            } catch (JsonProcessingException e) {
                log.error("Json读取异常", e);
            }
        }
        return null;
    }

    public static <T> void set(String key, T obj) {
        set(key, obj, TIME);
    }

    /**
     *
     * @param key
     * @param obj
     * @param expireTime
     * @param <T>
     */
    public static <T> void set(String key, T obj, Long expireTime) {
        synchronized (LOCK) {
            try {
                String value = new ObjectMapper().writeValueAsString(obj);
                map.put(key, value);
                expire.put(key, expireTime <= 0 ? TIME : System.currentTimeMillis() / 1000 + expireTime);
            } catch (JsonProcessingException e) {
                log.error("Json写入异常", e);
            }
        }
    }

    /**
     * 定时清除失效key
     */
    private static class ExpireTask extends Thread {

        @Override
        public void run() {
            long t;
            while (true) {
                try {
                    long now = System.currentTimeMillis() / 1000;
                    String[] keys = expire.keySet().toArray(new String[] {});
                    for (String key : keys) {
                        t = expire.get(key);
                        synchronized (LOCK) {
                            if (t > 0 && t < now) {
                                map.remove(key);
                                expire.remove(key);
                            }
                        }
                    }
                    Thread.sleep(1000);
                } catch (Exception e) {
                    log.error("", e);
                }
            }
        }
    }
}
